/*
=================================================================================
 Name        : Boids
 Author      : Anthony Eden
 Version     : 1.1
 Copyright   : N/A
 Description : Craig W. Reynold's Boids ported to C++ & Irrlicht 1.4 3d Engine
 Last Updated: July 11, 2008
=================================================================================
*/
//#define DEBUG

#include "boids.h"
#include "AE.h"


dimension2d<s32> windowSize(800, 600);

IrrlichtDevice* device;
IVideoDriver* driver;
ISceneManager* smgr;
IGUIEnvironment* guiEnv;
ITimer* timer;

float range_sep = 200.0f;
float range_align = 400.0f;
float range_cohes = 400.0f;
float scaleFac_sep = 200.0f;
float scaleFac_align = .003f;
float scaleFac_cohes = .005f;
bool keyDown_W, keyDown_S, keyDown_D, keyDown_A, mouseMoveEnabled, mouseMoveJustChanged, paused = false;

float playerSpeed = 2.2f;
float playerRotSpeed = 1.0f;
float xChng2= 0.0f;
float zChng2= 0.0f;
float xChng = 0.0f;
float zChng= 0.0f;


//int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR lpCmdLine, int)
int main()
{


	SIrrlichtCreationParameters par;
	par.AntiAlias = false;
	par.WindowSize = dimension2d<s32>(800 , 600);
	par.Bits = 16;
	par.Vsync = true;


	cout<<"\n *** Boids v1.2 ***\n"<<std::endl;

	char i;
	char aa;

	// Driver?
	std::cout<<\
		"\n Please select the driver type to use:\n\n"\
		"  (a) Direct3D 9.0c\n  (b) OpenGL 1.5\n"\
		"  (otherKey) exit\n"<<std::endl;

	std::cin >> i;

	switch(i)
	{
		case 'a':
			par.DriverType = EDT_DIRECT3D9;
			break;

		case 'b':
			par.DriverType = EDT_OPENGL;
			break;

		default: return 1;
	}

	if (par.DriverType == EDT_DIRECT3D9)
	{
		// AntiAlias?
		std::cout<<\
			"\n Please choose if you want anti-aliasing (supported only for D3D):\n\n"\
			"  (a) Yes\n  (b) No\n"\
			"  (otherKey) exit\n"<<std::endl;

		std::cin >> aa;

		switch(aa)
		{
			case 'a':
				par.AntiAlias= true;
				break;

			case 'b':
				par.AntiAlias= false;
				break;

			default: return 1;
		}
	}


	std::cout<<"\n\n\n"<<std::endl;

	device = createDeviceEx(par);
	driver = device->getVideoDriver();
	smgr = device->getSceneManager();
	guiEnv = device->getGUIEnvironment();
	timer = device->getTimer();

	makeBoidGui(windowSize);
//------------------------------------------------------------------------------------------------------------------------
	smgr->addSkyBoxSceneNode(
	driver->getTexture("media/3.bmp"),
	driver->getTexture("media/6.bmp"),
	driver->getTexture("media/5.bmp"),
	driver->getTexture("media/2.bmp"),
	driver->getTexture("media/1.bmp"),
	driver->getTexture("media/4.bmp"));
//------------------------------------------------------------------------------------------------------------------------
	vector <Boid*> boids;


	for (int i = 0; i < 50; i++)
	{	//                                                            T minx, T miny, T minz, T maxx, T maxy, T maxz
		boids.push_back(new Boid("media/boid.obj", "media/r001mapsall2.bmp", aabbox3d<f32>(0,0,0,4000,4000,4000)));
	}


//------------------------------------------------------------------------------------------------------------------------
	IAnimatedMeshSceneNode* beach = makeAnimatedSimpleObject("media/beach.obj", "media/SANDSHOR.JPG");
	IAnimatedMeshSceneNode* water = makeAnimatedSimpleObject("media/water.obj", "media/2537.jpg");
	beach->setPosition(beach->getPosition() + vector3df(0.0f,-1000.0f,0.0f));
	water->setPosition(water->getPosition() + vector3df(0.0f,-1000.0f,0.0f));
	
//------------------------------------------------------------------------------------------------------------------------
	ICameraSceneNode* cam = smgr->addCameraSceneNode();
	cam->setFarValue(100000.0f);
	cam->setPosition(vector3df(0.0f,10.0f,0.0f));
	cam->setFOV(45.0f*0.0174532925f);
//------------------------------------------------------------------------------------------------------------------------
	EventReciever receiver = EventReciever();
	device->setEventReceiver(&receiver);
//------------------------------------------------------------------------------------------------------------------------
	gui::IGUISkin* newSkin = guiEnv->createSkin(gui::EGST_BURNING_SKIN);
	guiEnv->setSkin(newSkin);
	newSkin->drop();

	IGUIFont* proggyFont = guiEnv->getFont("media/proggyFontIrr.xml");

	IGUIStaticText* txt = guiEnv->addStaticText(L"", rect<s32>(10, windowSize.Height - 60, 350, windowSize.Height - 45), 
		false, false, 0, 1, false);
	txt->setOverrideColor(SColor(255, 255,0,0));
	//Irllicht uses fonts that are in xml format
	txt->setOverrideFont(proggyFont);
//------------------------------------------------------------------------------------------------------------------------
	IGUIStaticText* txt2 = guiEnv->addStaticText(L"", rect<s32>(10, windowSize.Height -30, 350, windowSize.Height - 15), 
		false, false, 0, 1, false);
	txt2->setOverrideColor(SColor(255, 255,0,0));
	//Irllicht uses fonts that are in xml format
	txt2->setOverrideFont(proggyFont);
//------------------------------------------------------------------------------------------------------------------------
	IGUIStaticText* txt3 = guiEnv->addStaticText(L"", rect<s32>(10, windowSize.Height -90, 350, windowSize.Height - 75), 
		false, false, 0, 1, false);
	txt3->setOverrideColor(SColor(255, 255,0,0));
	//Irllicht uses fonts that are in xml format
	txt3->setOverrideFont(proggyFont);
//------------------------------------------------------------------------------------------------------------------------
	IGUIStaticText* txt4 = guiEnv->addStaticText(L"", rect<s32>(10, windowSize.Height -120, 350, windowSize.Height - 105), 
		false, false, 0, 1, false);
	txt4->setOverrideColor(SColor(255, 255,0,0));
	//Irllicht uses fonts that are in xml format
	txt4->setOverrideFont(proggyFont);
//------------------------------------------------------------------------------------------------------------------------
	int lastFPS = -1;
	float oldTime = 0.0f;
	float newTime = 0.0f;
	position2di newMouse = position2di(0,0);
	position2di oldMouse = position2di(0,0);
	vector3df camRot(0.0f,0.0f,0.0f);
	vector3df camPos(0.0f,0.0f,0.0f);

	ICursorControl* cursorControl = device->getCursorControl();

	cursorControl->setVisible(false);
	position2d<s32> forcedMouseChangeInPos(0,0);
	position2d<s32> transitionChangeMousePos(0,0);

	while (device->run())
	{

		driver->beginScene(true, true, SColor(255,100,101,140));

		if (!paused)
		{
			for (int i = 0; i < 50; i++)
			{
				boids[i]->updateBoid(boids,range_cohes, scaleFac_cohes, range_sep, scaleFac_sep, range_align,
					scaleFac_align, 50);
			}
		}


		newMouse = device->getCursorControl()->getPosition();
		newTime = (float)timer->getTime();

		if (mouseMoveEnabled)
		{
			if (mouseMoveJustChanged)
			{
				cursorControl->setVisible(true);
				cursorControl->setPosition(cursorControl->getPosition() + position2d<s32>(0,0));
				mouseMoveJustChanged = false;
			}
		}
		else
		{

			if (mouseMoveJustChanged)
			{
				transitionChangeMousePos = cursorControl->getPosition() - position2d<s32>(200,200);
				
				cursorControl->setVisible(false);
				cursorControl->setPosition(cursorControl->getPosition() + position2d<s32>(0,0));
				mouseMoveJustChanged = false;
				
				newMouse-= transitionChangeMousePos;
				
				
				
			}
			
			forcedMouseChangeInPos = position2d<s32>(200, 200) - cursorControl->getPosition();
			rotateCamWithMouse(cam, (newMouse.X - oldMouse.X) - forcedMouseChangeInPos.X, (newMouse.Y - oldMouse.Y) - forcedMouseChangeInPos.Y, false);
			cursorControl->setPosition(position2d<s32>(200, 200));
			
		}
		
		camRot = cam->getRotation();
		camPos = cam->getPosition();
		
		
		
		
		if (keyDown_W)
		{
			vector3df newPos = moveForwardRelativeToRotation(cam, newTime - oldTime, 1.0f);
			
			if (newPos.Y > 5.0f) cam->setPosition(newPos);
			
		}
		
		if (keyDown_S)
		{
			vector3df newPos = moveForwardRelativeToRotation(cam, newTime - oldTime, -1.0f);
			if (newPos.Y > 5.0f) cam->setPosition(newPos);
		}
		cam->setTarget(updateCamTarget(cam, 5.0f, newTime - oldTime));
		
		
		oldTime = (float)timer->getTime();
		oldMouse = device->getCursorControl()->getPosition();
		
		txt->setText((stringw("CAM_ROT: ") + stringw(camRot.X) + stringw(", ") + stringw(camRot.Y) + stringw(", ") + 
			stringw(camRot.Z)).c_str());
		txt2->setText((stringw("CAM_POS: ") + stringw(camPos.X) + stringw(", ") + stringw(camPos.Y) + stringw(", ") + 
			stringw(camPos.Z)).c_str());
		
		if (paused)txt3->setText(stringw("Boids Paused: True").c_str());
		else txt3->setText(stringw("Boids Paused: False").c_str());
		
		if (mouseMoveEnabled)txt4->setText(stringw("Mouse Movement Enabled: True").c_str());
		else txt4->setText(stringw("Mouse Movement Enabled: False").c_str());
		
		
		smgr->drawAll();
		guiEnv->drawAll();
		
		//cam->setPosition(cam->getPosition() + vector3df(0.0f, 0.0f, 1.0f));
		
		int fps = driver->getFPS();
		
		if (lastFPS != fps)
		{
			core::stringw title = L"Boids v1.1[";
			title += driver->getName();
			title += "] FPS:";
			title += fps;
			if (par.AntiAlias == true)
				title+=" | Anti-Aliasing: True";
			else
				title+=" | Anti-Aliasing: False";
			device->setWindowCaption(title.c_str());
			lastFPS = fps;
		}
		
		

		driver->endScene();
	

	}

	device->closeDevice();

	return 0;


}